#ifndef __WINDOW_HPP__
#define __WINDOW_HPP__ 1

#include <thread>
#include <mutex>

#include <Windows.h>

#include "Input.hpp"
#include "Event.hpp"

class CWindow;
class CRenderer;

struct WindowCreated : public EventData
{
	WindowCreated(CWindow* window) : window(window)
	{
	}
	~WindowCreated()
	{
	}

	void Destroy() { delete this; }
	CWindow* window;
};

struct WindowDestroyed : public EventData
{
	WindowDestroyed(CWindow* window) : window(window)
	{
	}

	void Destroy() { delete this; }
	CWindow* window;
};

struct WindowResize : public EventData
{
	WindowResize(int width, int height) : width(width), height(height)
	{
	}

	void Destroy() { delete this; }
	int width;
	int height;
};

#ifdef _WIN32
typedef HWND WindowHandle;
#elif
#warning Unsupported Platform
#endif

struct WindowOptions
{
	int screenX;
	int screenY;
	int width;
	int height;
	int redbits;
	int greenbits;
	int bluebits;
	int alphabits;
	int depthbits;
	int stencilbits;
	int mode;
};

struct WindowContext : public WindowOptions
{
	int windowId;
#ifdef _WIN32
	WindowHandle handle;
	HINSTANCE	hInstance;
	ATOM classAtom;
	DWORD dwStyle;
	DWORD dwExStyle;
	HDC hDC;
#elif
#error Unsupported Platform
#endif
};

class CWindow : public WindowContext
{
public:
	CWindow(WindowOptions* windowOptions, EventHandler& eventHandler) : eventHandler(eventHandler)
	{
		screenX = windowOptions->screenX;
		screenY = windowOptions->screenY;
		height = windowOptions->height;
		width = windowOptions->width;
		depthbits = windowOptions->depthbits;
		stencilbits = windowOptions->stencilbits;
		alphabits = windowOptions->alphabits;
		bluebits = windowOptions->bluebits;
		greenbits = windowOptions->greenbits;
		redbits = windowOptions->redbits;

		thr = std::thread(&CWindow::WindowThread, this, std::ref(eventHandler));
	}
	~CWindow()
	{
		WindowDestroy();

		::UnregisterClassW(L"BattleBots", hInstance);

		thr.join();
	}

	void WindowCreate();
	void WindowDestroy();

	void GetWindowDimensions(int* sizeX, int* sizeY);
	void SetWindowDimensions(int sizeX, int sizeY);

	void SetThread(std::thread&& thread) { thr = std::move(thread); }
	std::thread& GetThread() { return std::ref(thr); }
	//std::unique_lock<std::mutex> GetLock() { return std::unique_lock<std::mutex>(mtx); }
	
	int WindowThread(EventHandler& eventHandler);

	static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
	LRESULT CALLBACK MsgHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

	// Event handlers
	bool OnWindowResize(Event* evt);
private:
	EventHandler& eventHandler;
	std::thread thr;
	//std::mutex mtx;
	CWindow(CWindow&) : eventHandler(eventHandler) { }
	const CWindow& operator=(const CWindow&) { }
};

#endif